/*
 * =====================================================================================
 *
 *       Filename:  World.cpp
 *
 *    Description:  implementation of World class
 *
 *        Version:  1.0
 *        Created:  01/05/12 02:01:44
 *       Revision:  none
 *       Compiler:  g++
 *
 *         Author:  LittleQ Su (), 98703060@nccu.edu.tw
 *        Company:  National Chengchi University, The Department of Computer Science
 *
 * =====================================================================================
 */
#include "World.h"
#include "Goat.h"
#include "Grass.h"

World::World(int pass_times, int seed) {
    this -> random = new RandomNum(seed);
    _max_times = pass_times;
    cleanWorld();
    init();

    printWorld();
}

World::~World() {
    
}

void World::mainLoop(int displayInterval) {

    while ( _pass_times < _max_times ) {
        if ( (_pass_times%displayInterval) == 0 ) {
            printWorld();
            sleep(1);
        }
        
        action();
        

        _pass_times++;
    }
    printWorld();

}
void World::init() {
    const int X=35, Y=20;
    enum CREATURE_TYPE temp = GOAT;
    // add goats
    for (int i = 0 ; i < 15 ; ++i ) {
        if ( !addCreature(temp, random->getRandomNum(0,X-1), random->getRandomNum(0,Y-1)) ) {
            i--;
        }
        if ( i == 9 ) temp = GRASS;
    }

}

int World::getRandom(int low, int high) {
    return this -> random -> getRandomNum(low, high);
}

enum CREATURE_TYPE World::getCreature(int x, int y) {
    if ( _p_world[x][y] == NULL ) {
        return NOONE;
    } else {
        return _p_world[x][y] -> get_identify_word();
    }
}

void World::action() {
    for ( int x = 0 ; x < width ; ++x ) {
        for ( int y = 0 ; y < height ; ++y ) {
            if ( _p_world[x][y] == NULL || _p_world[x][y] -> getMoved() ) continue;
            else { 
                _p_world[x][y] -> action();
            }
        }
    }
    for ( int x = 0 ; x < width ; ++x ) {
        for ( int y = 0 ; y < height ; ++y ) {
            if ( _p_world[x][y] != NULL ) {
                _p_world[x][y] -> setMoved(false);
            }
        }
    }
}

void World::printWorld() const {
    system("clear");
    int goats_num = 0, grass_num = 0;
    // First header
    cout << "  ";
    for ( int i = 0 ; i < this->width ; ++i ) cout << " " << (i%10);
    cout << endl;

    // Left rows
    for ( int y = 0 ; y < height ; ++y ) {
        cout << " " << (y%10) ;
        for ( int x = 0 ; x < width ; ++x ) {
            if ( _p_world[x][y] == NULL ) {
                cout << "  ";
            } else if ( _p_world[x][y] -> get_identify_word() == GOAT ) {
                cout << " X";
                goats_num++;
            } else if ( _p_world[x][y] -> get_identify_word() == GRASS ) {
                cout << " I";
                grass_num++;
            }
        }
        cout << endl;
    }

    // Information bar
    for ( int i = 0 ; i <= width ; ++i ) cout << "--"; cout << endl;
    cout << "Pass: " << _pass_times << ", ";
    //cout << "Wolfs: " << _p_wolfs.size() << ", "; // Where's the wolves?
    cout << "Goat: " << goats_num << ", ";
    cout << "Grass: " << grass_num << endl;

}

void World::cleanWorld() {
    for ( int x = 0 ; x < width ; ++x ) {
        for ( int y = 0 ; y < height ; ++y ) {
            _p_world[x][y] = NULL;
        }
    }
    _pass_times = 0;
}

bool World::addCreature( enum CREATURE_TYPE type, int x, int y) {
    if ( _p_world[x][y] != NULL ) {
        cout << "duplicated creature!" << endl;
        return false;
    }

    Creature *newCreature;
    if ( type == GOAT ) {
        newCreature = new Goat( this , x , y );
    } else if ( type == GRASS ) {
        newCreature = new Grass( this , x , y );
    }

    _p_world[x][y] = newCreature;

    return true;
}

void World::moveCreature( int old_x, int old_y, int new_x, int new_y) {
    _p_world[new_x][new_y] = _p_world[old_x][old_y];
    _p_world[old_x][old_y] = NULL;
}

void World::removeCreature( int x, int y ) {
    delete _p_world[x][y]; 
    _p_world[x][y] = NULL;
}
